package com.ibeeking.found.upms.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ibeeking.found.common.base.BaseDO;
import com.ibeeking.found.common.config.feign.GlobalClient;
import com.ibeeking.found.common.config.prop.FileOssProp;
import com.ibeeking.found.common.constants.DefaultPathConstant;
import com.ibeeking.found.common.enums.JobStatusEnum;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.SexEnum;
import com.ibeeking.found.common.utils.UrlUtils;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.upms.b.rest.config.prop.UserConfigProp;
import com.ibeeking.found.upms.b.rest.service.ICpRoleService;
import com.ibeeking.found.upms.b.rest.service.ICpUserRoleService;
import com.ibeeking.found.upms.b.rest.service.ICpUserService;
import com.ibeeking.found.upms.service.common.bo.CpRoleBO;
import com.ibeeking.found.upms.service.common.bo.CpUserRoleBO;
import com.ibeeking.found.upms.service.common.bo.TenantUserBO;
import com.ibeeking.found.upms.service.common.bo.TenantUserRoleBO;
import com.ibeeking.found.upms.service.common.dos.TenantUserDO;
import com.ibeeking.found.upms.service.common.param.TenantUserParam;
import com.ibeeking.found.upms.service.common.query.TenantUserPageQuery;
import com.ibeeking.found.upms.service.common.vo.GmcUserPageVO;
import com.ibeeking.found.upms.service.common.vo.TenantUserVO;
import com.ibeeking.found.upms.service.mapper.CpUserMapper;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName CsUserServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-04-28 11:46
 **/
@Service
public class CpUserServiceImpl implements ICpUserService {

    @Resource
    private CpUserMapper cpUserMapper;
    @Resource
    private GlobalClient globalClient;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private FileOssProp fileOssProp;
    @Resource
    private UserConfigProp userConfigProp;
    @Resource
    private ICpUserRoleService cpUserRoleServiceImpl;
    @Resource
    private ICpRoleService cpRoleServiceImpl;

    @Override
    public Page<GmcUserPageVO> pageList(TenantUserPageQuery query) {
        LambdaQueryWrapper<TenantUserDO> queryWrapper = new LambdaQueryWrapper<>(TenantUserDO.class)
                .orderByDesc(BaseDO::getCreateTime)
                .eq(null != query.getPublishStatus(), TenantUserDO::getPublishStatus, query.getPublishStatus())
                .eq(null != query.getJob(), TenantUserDO::getJob, query.getJob())
                .eq(null != query.getSex(), TenantUserDO::getSex, query.getSex())
                .like(StringUtils.isNotBlank(query.getTel()), TenantUserDO::getTel, query.getTel())
                .like(StringUtils.isNotBlank(query.getName()), TenantUserDO::getName, query.getName())
                .like(StringUtils.isNotBlank(query.getMobile()), TenantUserDO::getMobile, query.getMobile())
                .like(StringUtils.isNotBlank(query.getEmail()), TenantUserDO::getEmail, query.getEmail());
        Page<TenantUserDO> csUserDOPage = cpUserMapper.selectPage(new Page<>(query.getPageNum(), query.getPageSize()), queryWrapper);
        Page<GmcUserPageVO> result = BeanUtil.convertPage(csUserDOPage, GmcUserPageVO.class);

        if (!Collections3.isEmpty(result.getRecords())) {
            Map<Long, StringBuffer> map = new HashMap<>();

            //查询角色
            List<CpUserRoleBO> csUserRoleBos = cpUserRoleServiceImpl.queryRoleIdsByUserIds(result.getRecords().stream().map(GmcUserPageVO::getId).collect(Collectors.toList()));
            if (!Collections3.isEmpty(csUserRoleBos)) {
                List<CpRoleBO> csRoleBos = cpRoleServiceImpl.queryByIds(csUserRoleBos.stream().map(CpUserRoleBO::getRoleId).distinct().collect(Collectors.toList()));
                if (!Collections3.isEmpty(csRoleBos)) {
                    Map<Long, String> roleMap = csRoleBos.stream().collect(Collectors.toMap(CpRoleBO::getId, CpRoleBO::getName, (s, a) -> a));
                    csUserRoleBos.stream().filter(s -> roleMap.containsKey(s.getRoleId())).forEach(s -> {
                        if (map.containsKey(s.getUserId())) {
                            map.get(s.getUserId()).append(roleMap.get(s.getRoleId())).append(",");
                        } else {
                            map.put(s.getUserId(), new StringBuffer(roleMap.get(s.getRoleId())).append(","));
                        }
                    });
                }
            }
            for (GmcUserPageVO csUserPageVO : result.getRecords()) {
                csUserPageVO.setSexName(SexEnum.getDescByCode(csUserPageVO.getSex()));
                csUserPageVO.setPublishStatusDesc(PublishStatusEnum.getName(csUserPageVO.getPublishStatus()));
                csUserPageVO.setJobDesc(JobStatusEnum.getDescByCode(csUserPageVO.getJob()));
                if (map.containsKey(csUserPageVO.getId())) {
                    csUserPageVO.setRoleName(map.get(csUserPageVO.getId()).toString());
                }
            }
        }
        return result;
    }

    @Override
    public Boolean add(TenantUserParam param) {
        TenantUserDO csUserDO = BeanUtil.convertBean(param, TenantUserDO.class);
        List<Long> ids = cpUserMapper.checkUnique(getTenantIds(), param.getMobile());
        if (!Collections3.isEmpty(ids)) {
            throw new BusinessException("当前手机号已存在");
        }
        if (StringUtils.isBlank(param.getImage())) {
            csUserDO.setImage(DefaultPathConstant.DEFAULT_USER_HEAD_IMAGE);
        }
        csUserDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
        csUserDO.setJob(PublishStatusEnum.ENABLE.getValue());
        csUserDO.setUserCode(param.getMobile());
        csUserDO.setPassword(passwordEncoder.encode(userConfigProp.getInitialPwd()));
        csUserDO.setCreateBy(UserUtils.getUserId());
        csUserDO.setCreateTime(LocalDateTime.now());
        csUserDO.setModifyTime(LocalDateTime.now());
        return cpUserMapper.insert(csUserDO) > 0;
    }

    @Override
    public Boolean modify(TenantUserParam param) {
        TenantUserDO csUserDO = BeanUtil.convertBean(param, TenantUserDO.class);
        csUserDO.setMobile(null);
        csUserDO.setModifyBy(UserUtils.getUserId());
        csUserDO.setModifyTime(LocalDateTime.now());
        return cpUserMapper.updateById(csUserDO) > 0;
    }

    @Override
    public TenantUserVO view(Long id) {
        return BeanUtil.convertBean(getBean().queryById(id), TenantUserVO.class);
    }

    @Override
    public TenantUserBO queryById(Long id) {
        TenantUserDO csUserDO = cpUserMapper.selectById(id);
        csUserDO.setImage(UrlUtils.addUrlDomainName(fileOssProp.getHost(), csUserDO.getImage()));
        return BeanUtil.convertBean(csUserDO, TenantUserBO.class);
    }

    @Override
    public Boolean lock(Long id, Integer status) {
        TenantUserDO csUserDO = new TenantUserDO();
        csUserDO.setId(id);
        csUserDO.setPublishStatus(status);
        csUserDO.setModifyBy(UserUtils.getUserId());
        csUserDO.setModifyTime(LocalDateTime.now());
        return cpUserMapper.updateById(csUserDO) > 0;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean quit(Long id) {
        TenantUserDO csUserDO = new TenantUserDO();
        csUserDO.setId(id);
        csUserDO.setPublishStatus(PublishStatusEnum.DISABLE.getValue());
        csUserDO.setJob(PublishStatusEnum.DISABLE.getValue());
        csUserDO.setModifyBy(UserUtils.getUserId());
        csUserDO.setModifyTime(LocalDateTime.now());
        cpUserRoleServiceImpl.delByUserId(id);
        return cpUserMapper.updateById(csUserDO) > 0;
    }

    @Override
    public Boolean del(Long id) {
        if (PublishStatusEnum.ENABLE.getValue().equals(getBean().queryById(id).getJob())) {
            throw new BusinessException("请先离职员工后再删除");
        }
        return cpUserMapper.deleteById(id) > 0;
    }

    @Override
    public Boolean resetPwd(Long id) {
        TenantUserDO csUserDO = new TenantUserDO();
        csUserDO.setId(id);
        csUserDO.setPassword(passwordEncoder.encode(userConfigProp.getInitialPwd()));
        csUserDO.setModifyTime(LocalDateTime.now());
        return cpUserMapper.updateById(csUserDO) > 0;
    }

    @Override
    public List<TenantUserVO> listByNameOrMobile(String nameOrMobile) {
        List<TenantUserDO> csUserDos = cpUserMapper.selectList(new LambdaQueryWrapper<>(TenantUserDO.class)
                .orderByDesc(BaseDO::getCreateTime)
                .eq(TenantUserDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(TenantUserDO::getJob, PublishStatusEnum.ENABLE.getValue())
                .and(!"null".equalsIgnoreCase(nameOrMobile) && StringUtils.isNotBlank(nameOrMobile),
                        Wrapper -> Wrapper
                                .like(TenantUserDO::getName, nameOrMobile)
                                .or()
                                .like(TenantUserDO::getMobile, nameOrMobile)
                )
        );
        return JsonUtils.jsonToList(csUserDos, TenantUserVO.class);
    }

    private static ICpUserService getBean() {
        return SpringBeanUtil.getBean(ICpUserService.class);
    }

    private List<Integer> getTenantIds() {
        ResponseResult<List<Integer>> responseResult = globalClient.queryTenantIds();
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            throw new BusinessException("租户不存在");
        }
        return responseResult.getData();
    }
}
